package com.cooper.android.comm;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public abstract class ResourcePool<T> {

	private int maxCount = Integer.MAX_VALUE;
	private int minCount = 0;
	private int count = 0;
	private List<T> idieResources = new ArrayList<T>();
	private List<T> busyResources = new ArrayList<T>();
	private final Lock lock = new ReentrantLock();

	public ResourcePool(int maxCount, int minCount, int count) {
		this.maxCount = maxCount;
		this.minCount = minCount;
		this.count = count;
		init();
	}

	public ResourcePool(int count) {
		this.count = count;
		init();
	}

	public Integer getMaxCount() {
		return maxCount;
	}

	public void setMaxCount(Integer maxCount) {
		this.maxCount = maxCount;
	}

	public int getMinCount() {
		return minCount;
	}

	public void setMinCount(int minCount) {
		this.minCount = minCount;
	}

	public int getInitCount() {
		return count;
	}

	public void setInitCount(int initCount) {
		this.count = initCount;
	}

	private void init() {
		for (int i = 0; i < minCount; i++) {
			idieResources.add(createResource());
		}

	}

	public T getResource() throws PooloutException {
		lock.lock();
		try {
			T result;
			if (idieResources.size() > 0) {
				result = idieResources.get(0);
				idieResources.remove(0);
			} else if ((busyResources.size() + idieResources.size()) < maxCount) {
				result = createResource();
			} else {
				throw new PooloutException();
			}
			busyResources.add(result);
			return result;
		} finally {
			lock.unlock();
		}
	}

	public void putResource(T resource) {
		lock.lock();
		try {
			if (busyResources.remove(resource)) {
				if (idieResources.size() > count) {
					destroyResource(resource);
				} else
					idieResources.add(resource);
			}
		} finally {
			lock.unlock();
		}
	}

	public void reset() {
		lock.lock();
		try {
			for (T res : idieResources) {
				destroyResource(res);
			}
			idieResources.clear();
			for (T res : busyResources) {
				destroyResource(res);
			}
			busyResources.clear();
			init();
		} finally {
			lock.unlock();
		}
	}

	protected abstract T createResource();

	protected abstract void destroyResource(T resource);

	public static class PooloutException extends Exception {

		/**
		 * 
		 */
		private static final long serialVersionUID = -4466038875366542596L;

	}

}
